package com.star.security.config;

import com.star.security.authentication.AuthenticationManager;
import com.star.security.authentication.AuthenticationManagerImpl;
import com.star.security.authentication.AuthenticationProvider;
import com.star.security.authentication.usernamepassword.UsernamePasswordAuthenticationProvider;
import com.star.security.authentication.wxapp.WxappAuthenticationApi;
import com.star.security.authentication.wxapp.WxappAuthenticationApiImpl;
import com.star.security.authentication.wxapp.WxappAuthenticationProvider;
import com.star.security.authentication.wxapp.Wxapp;
import com.star.security.context.RedissonTokenRepository;
import com.star.security.context.TokenRepository;
import com.star.security.filter.AccessCheckerImpl;
import com.star.security.filter.AccessInterceptor;
import com.star.security.filter.AnonymousAuthenticationRequestImpl;
import com.star.security.filter.TokenContextHolderFilter;
import com.star.security.authentication.AuthenticationService;
import com.star.security.authentication.AuthenticationServiceImpl;
import com.star.security.user.UserDetailsService;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 安全配置
 *
 * @author yangzj
 */
@EnableConfigurationProperties({SecurityProperties.class, Wxapp.class})
@Configuration
public class SecurityConfig implements WebMvcConfigurer {

    @Resource
    private RedissonClient redisson;
    @Resource
    private SecurityProperties securityProperties;
    @Resource
    private Wxapp wxapp;
    @Resource
    private UserDetailsService userDetailsService;

    /*@ConditionalOnMissingBean
    @Bean
    public UserDetailsService userDetailsService() {
        User user = new User().setPassword(PasswordEncoders.encode("123456"))
                .setRoles(Collections.singleton("admin")).setSuperAdmin(false)
                .setEnabled(true);
        return new UserDetailsService() {
            @Override
            public User getByUsername(String username) {
                return user.setUsername(username);
            }

            @Override
            public User getByOpenId(String openId) {
                return user.setUsername(openId).setOpenId(openId);
            }

            @Override
            public User register(String openId, String unionId) {
                return user.setUsername(openId).setOpenId(openId).setUnionId(unionId);
            }
        };
    }*/

    @ConditionalOnMissingBean
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public WxappAuthenticationApi wxappAuthenticationApi() {
        return new WxappAuthenticationApiImpl(wxapp, redisson, restTemplate());
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> providers = new ArrayList<>();
        providers.add(new UsernamePasswordAuthenticationProvider(userDetailsService));
        providers.add(new WxappAuthenticationProvider(userDetailsService, wxappAuthenticationApi()));
        return new AuthenticationManagerImpl(providers);
    }


    @Bean
    public TokenRepository tokenRepository() {
        return new RedissonTokenRepository(redisson);
    }

    @Bean
    public FilterRegistrationBean<TokenContextHolderFilter> tokenContextHolderFilter() {
        FilterRegistrationBean<TokenContextHolderFilter> registrationBean = new FilterRegistrationBean<>();
        // 设置匿名uri
        AnonymousAuthenticationRequestImpl anonymous = new AnonymousAuthenticationRequestImpl(securityProperties.getAnonymousUris());
        registrationBean.setFilter(new TokenContextHolderFilter(tokenRepository(), anonymous));
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("tokenContextHolderFilter");
        // 设置为最高优先级
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AccessInterceptor(new AccessCheckerImpl())).addPathPatterns("/**");
    }

    @Bean
    public AuthenticationService authenticationService(){
        return new AuthenticationServiceImpl(tokenRepository(), authenticationManager());
    }
}
